#! user/bin/python
# -*- coding: utf-8 -*-

"""
Created on 2021/8/24 9:38

@File: 简单的命令行模式_getfile.py
@Author: LT
@Description: 实现了服务器端和客户端的需求逻辑，通过原始套接字
              让客户端发送本地文件名给服务器，服务器打开文件读取数据再传到客户端机器上，形成client_开通的文件
"""
import sys
import os
import time
import threading
from socket import *

block_size = 1024
default_host = 'localhost'
default_port = 50001

help_text = """
Usage...
server=> 简单的命令行模式_getfile.py  -mode server                       [-port nnn] [-host hhh|localhost]
client=> 简单的命令行模式_getfile.py [-mode client] -file local_filename [-port nnn] [-host hhh|localhost]
"""


def now():
    return time.asctime()


def parse_commandline():
    """解析命令行的函数"""
    dict = {}                                               # 放到字典里方便浏览
    args = sys.argv[1:]
    while len(args) >= 2:
        dict[args[0]] = args[1]
        args = args[2:]
    return dict


def client(host, port, filename):
    sock = socket(AF_INET, SOCK_STREAM)
    sock.connect((default_host, default_port))
    sock.send((filename + '\n').encode())
    dropdir = os.path.split(filename)[1]                    # 这个函数是用来分离目录名和文件名的，返回一个2-元组，第二个元素文件名
    file = open("client_" + dropdir, "wb")                              # 二进制模式写入文件，新的文件名会以client_开头
    while True:
        data = sock.recv(block_size)                        # 接收1024B也就是1k大小的数据
        if not data:                                        # 一直接收直到服务器端关闭
            break
        file.write(data)                                    # 在客户端本地存储从服务器接收到的数据
    sock.close()
    file.close()
    print("Client got", filename, 'at', now())


def serverthread(clientsock):
    sockfile = clientsock.makefile("r")                     # 封装套接字
    filename = sockfile.readline()[:-1]                     # 接收客户端发来的文件名，切片正好把末尾的\n换行符给切掉了
    print(f"Server got {filename} from client:{clientsock}")
    try:
        file = open(filename, "rb")
        while True:
            _bytes = file.read(block_size)                  # 一次读取/发送1k大小的数据
            if not _bytes:
                break
            sent = clientsock.send(_bytes)
            assert sent == len(_bytes)                      # 简单的校验，接收的与发送的长度不等
    except:
        print('Error downloading file on server:', filename)
    clientsock.close()


def server(host, port):
    serversock = socket(AF_INET, SOCK_STREAM)
    serversock.bind((host, port))
    serversock.listen()
    while True:
        clientsock, clientaddress = serversock.accept()     # 一直阻塞，直到客户端连接上来
        print('Server connected by', clientaddress, 'at', now())
        threading.Thread(target=serverthread, args=(clientsock,)).start()


def main(args):
    """
    总调用程序：
    """
    if args:
        print(f"What I get is {args}")
    host = args.get("-host", default_host)                  # 没有-host关键字则用default_host代替
    port = int(args.get("-port", default_port))
    if args.get("-mode") == 'server':                       # 把-mode指定为server才能设定为服务器模式，否则默认为客户端模式
        if host == "localhost":
            host = ""
        else:
            assert False, "远程连接暂未完善，还不可用"
        server(host, port)
    elif args.get("-file"):
        client(host, port, args["-file"])
    else:
        print(help_text)


if __name__ == '__main__':
    args = parse_commandline()
    main(args)
